#include <stdio.h>
#include <string.h>

#include "config.h"
#include "STC32G_Timer.h"
#include "STC32G_GPIO.h"
#include "STC32G_NVIC.h"
#include "STC32G_Exti.h"
#include "STC32G_Delay.h"

#include "app_config.h"
#include "drv_sd.h"
#include "debug.h"

#if TCFG_DRV_SD_CARD_SPI_SUPPORT

#define SD_CS   P77     // CS  片选
#define SD_DI   P76     // DI  CMD/DataIn
#define SD_CLK  P75     // CLK 时钟
#define SD_DO   P74     // DO  DataOut


static uint8_t sd_card_type = 0;
static uint8_t spi_speed = 0; // 0:低速（SD卡初始化阶段0~400KHz），1：高速(0~25MHz)

static struct sd_cardinfo_t sd_cardinf;



/**
 * @brief   设置SPI时钟频率
 * @param   speed:0=低速模式，1:高速模式
*/
void SD_SpiSpeedSet(uint8_t speed)
{
    spi_speed = speed;
}

/**
 * @brief   SPI读1个字节
*/
uint8_t SD_Read(void)
{
    uint8_t i,dat=0;
    SD_DO = 1;  // 设置为输入状态
    if (spi_speed) {
        // 24M晶振 SPI约2MHz左右
        for (i=0; i<8; i++)
        {
            SD_CLK = 0;
            dat<<=1;
            SD_CLK = 1;
            dat|=SD_DO;        
        }
    } else {
        // 24M晶振 SPI约300KHz左右
        for (i=0; i<8; i++)
        {
            SD_CLK = 0;
            delay_us(2);
            dat<<=1;
            SD_CLK = 1;
            delay_us(2);       
            dat|=SD_DO;        
        }
    }
    
    return dat;
}

/**
 * @brief   写一个字节数据到SD卡，模拟SPI模式
*/
void SD_Write(uint8_t dat)
{
    uint8_t i;
    if (spi_speed) {
        // 24M晶振 SPI约2MHz左右
        for (i=8; i>0; i--)
        {
            SD_CLK = 0;
            SD_DI = (dat&0x80);
            dat <<=1;
            SD_CLK = 1;
        }
    } else {
        // 24M晶振 SPI约300KHz左右
        for (i=8; i>0; i--)
        {
            SD_CLK = 0;
            delay_us(1);
            SD_DI = (dat&0x80);
            dat <<=1;
            delay_us(1);
            SD_CLK = 1;
            delay_us(2);       
        }
    }
    SD_DI = 1;
}

/**
 * @brief   SPI读取写入1个字节数据，双工模式
 * @param   dat:写入字节数据
 * @return  返回1字节读取数据
 */
uint8_t SD_ReadWrite(uint8_t dat)
{
    uint8_t r=0;
    uint8_t i,n=0;
    if (spi_speed) {
        // 24M晶振 SPI约2MHz左右
        for (i=8; i>0; i--)
        {
            SD_CLK = 0;
            SD_DI = (dat&0x80);
            dat <<=1;
            r<<=1;
            SD_CLK = 1;
            r|=SD_DO;
        }
    } else {
        // 24M晶振 SPI约300KHz左右
        for (i=8; i>0; i--)
        {
            SD_CLK = 0;
            delay_us(1);
            SD_DI = (dat&0x80);
            dat <<=1;
            delay_us(1);
            SD_CLK = 1;
            r<<=1;
            r|=SD_DO;
            delay_us(2);       
        }
    }
    SD_DI = 1;
    return r;
}

/**
 * @brief   读取命令响应 1字节
 * @return  返回响应数据
*/
uint8_t SD_Response()
{
    uint8_t i=0;
    uint8_t response=0;
    for (i=0; i<10; i++)
    {
        response = SD_Read();
        if (0x00 == response)
        {
            break;
        }
        if (0x01 == response)
        {
            break;
        }
    }

    return response;
}

/**
 * @brief   SD写入命令
 * @param   cmd:命令索引
 * @param   arg:命令参数，4字节长度
 * @param   crc:命令CRC  SPI模式只有CMD0,CMD8需要CRC， 其他命令填充0xFF即可
*/
void SD_Command(uint8_t cmd, uint32_t arg, uint8_t crc)
{
    SD_Write(cmd|0x40); // 位或40 添加方向位为1， 01XXXXXX
    SD_Write(((uint8_t *)&arg)[0]);
    SD_Write(((uint8_t *)&arg)[1]);
    SD_Write(((uint8_t *)&arg)[2]);
    SD_Write(((uint8_t *)&arg)[3]);
    SD_Write(crc);
    SD_Write(0xFF); // 命令发送之后，在发送8个CLK使SD卡完成内部操作；
}

/**
 * @brief   SD写入应用命令
 * @param   cmd:命令索引
 * @param   arg:命令参数，4字节长度
 * @param   crc:命令CRC  SPI模式只有CMD0,CMD8需要CRC， 其他命令填充0xFF即可 
*/
void SD_AppCommand(uint8_t cmd, uint32_t arg, uint8_t crc)
{
    SD_Command(CMD55_APP_CMD, 0, 0xFF);
    SD_Response();  // 正常返回0x01,这里只读取没做判断
    SD_Command(cmd, arg, crc);
}

/**
 * @brief   读取单块数据
 * @param   buffer:数据缓存指针，读取512个字节数据
 * @param   address:写入数据的开始地址，必须为512的整数倍
 * @return  0:成功，1：失败
*/
uint8_t SD_ReadSingelBlock(uint8_t*buffer, unsigned long address)
{
    /*
    读单单块流程：
    1.发送CMD17, 收到0x00表示成功
    2.连续读直到读到开始字节0xFE
    3.读取512个字节，1个块的size
    4.读取两个字节CRC数据，不管是否需要CRC校验，但必须读取2字节CRC
    */
    uint8_t response;
    unsigned int i,retrys;
    uint8_t rcode=0;
    uint8_t crc[2];

    SD_CS = 0;
    SD_Command(CMD17_READ_SINGLE_BLOCK, address, 0xFF); // CMD17 : 单块读取命令，回复0x00表示成功，之后一直读直到读到0xFE开始字节，
    retrys = 1000;
    do {
        response = SD_Response();
    }while((response!=0x00)&&--retrys);
    if (response != 0x00) {
        // 出错
        rcode = 1;
        goto exit;
    }

    // TODO: 循环读取开始字节0xFE
    retrys = 5000;
    do {
        response = SD_Read();
    }while((response != 0xFE)&&--retrys);
    if (response == 0xFE) {
        // 开始读取512字节数据
        for (i=0; i<SD_BLOCKSIZE; i++)
        {
            buffer[i] = SD_Read();   // 读数据
        }

        // 读取2字节CRC，这里不做处理
        crc[0] = SD_Read();
        crc[1] = SD_Read();
    } else {
        // 出错
        rcode = 1;
    }

exit:
    SD_CS = 1;
    SD_Write(0xFF);  // 8个空脉冲
    // log_d("CRC:0x%02x%02x\n", crc[0], crc[1]);
    return rcode;
}

uint8_t SD_WriteSingleBlock(uint8_t *buffer, uint32_t address)
{
    /*
    写单块流程：
    1.拉低CS,发送CMD24,连续读直到收到0x00表示成功
    2.发送8个字节时钟周期
    3.写入开始字节0xFE
    4.写入512个字节数据
    5.写入2字节CRC（可以全为0xFF）
    6.连续读直到读到XXX0_0101b表示数据写入成功
    7.继续读取进行忙检测（读到0x00表示SD卡正在忙状态，即DO拉低），当读到0xFF表示写入操作完成
    8.拉高CS,发送8个时钟周期
    */

    uint8_t response=0;
    uint8_t response_wr=0; // 写操作成功影响
    unsigned int i,n,retrys;
    uint8_t crc[2];
    uint8_t rcode=0;

    SD_CS = 0;
    SD_Command(CMD24_WRITE_SINGLE_BLOCK, address, 0xFF); // CMD24 : 单块写入
    
    retrys = 1000;
    do {
        response = SD_Response();   // 等待回复0x00表示成功
    }while((response != 0x00)&&--retrys);
    
    if (response != 0x00) {
        // 出错
        rcode = 1;
        goto exit;
    }

    // 写入若干时钟周期,这里写入10个字节
    retrys = 10;
    do {
        SD_Write(0xFF);
    }while(retrys--);

    // 写入开始字节0xFE块头部，后面跟512字节数据+2字节CRC数据
    SD_Write(0xFE);

    // 写入512字节数据
    for(i=0; i<512; i++)
    {
        SD_Write(buffer[i]);
    }

    // 写入2字节CRC
    SD_Write(0xFF);
    SD_Write(0xFF);

    // 读取
    response_wr = SD_Read()&0x0F;  //写入CRC码后SD卡会回应一个xxx0,1001   之后SD卡会把DO引脚拉低处于忙状态，知道释放DO引脚表示写入操作完成
    retrys = 10000;
    do {
        response = SD_ReadWrite(0xFF);  // 读到0x00表示SD卡忙状态，其他表示写入操作完成
    }while((0x00==response)&&--retrys);

    if (response_wr == 0x05) {
        // 成功
        rcode = 0;
    } else {
        // 出错
        rcode = 1;
    }

exit:
    SD_CS = 1;
    SD_Write(0xFF);
    return rcode;
}

uint8_t SD_ReadMultipleBlock(uint8_t *buffer, uint32_t address, uint32_t block_cnt)
{
    /*
    读多块的流程：
    1.发送CMD18,读到0x00表示成功
    2.连续读直到读到开始字节0xFE
    3.读取512字节
    4.读取2字节CRC
    5.需要读下一扇区，重复2,4步骤
    6.发送CMD12来停止传输
    */

    uint8_t response;
    unsigned int i,n,retrys;
    uint8_t crc[2];
    uint8_t rcode=0;

    SD_CS = 0;
    SD_Command(CMD18_READ_MULTIPLE_BLOCK, address, 0xFF); // CMD17 : 单块读取
    retrys = 1000;
    do {
        response = SD_Response();
    }while((response!=0x00)&&--retrys);
    if (response != 0x00) {
        // 出错
        rcode = 1;
        goto exit;
    }

    // 循环读取block_cnt个块数据
    for (n=0; n<block_cnt; n++)
    {
        retrys = 5000;
        do {
            response = SD_Read();
        }while((response!=0xFE)&&--retrys);
        if (response != 0xFE) {
            // 出错
            rcode = 1;
            goto exit;
        }

        // 开始读取512字节数据
        for (i=0; i<SD_BLOCKSIZE; i++)
        {
            buffer[n*SD_BLOCKSIZE+i] = SD_Read();   // 读数据
        }
        // 读取2字节CRC，这里不做处理，但异一定要读取出来！！
        crc[0] = SD_Read();
        crc[1] = SD_Read();
    }
    
    // 所有块字节数据读取完成后，发送CMD12命令停止传输
    SD_Command(CMD12_STOP_TRANSMISSION, 0, 0xFF);   // CMD12命令停止传输，正常响应0x00    
    retrys = 10000;
    do {
        response = SD_Response();
    }while((response!=0x00)&&--retrys);
    
    if (response!=0x00) {
        rcode = 1;  // 出错
    }

exit:
    SD_CS = 1;
    SD_Write(0xFF);  // 8个空脉冲
    // log_d("CRC:0x%02x%02x\n", crc[0], crc[1]);

    return rcode;
}


uint8_t SD_WriteMultipleBlock(uint8_t *buffer, uint32_t address, uint32_t block_cnt)
{
/*
写多块流程：
1.拉低CS,发送CMD25,连续读直到收到0x00表示成功
2.发送若干个字节时钟周期，这里发送10字节时钟
3.写入开始字节0xFC
4.写入512个字节数据
5.写入2字节CRC（可以全为0xFF）
6.连续读直到读到XXX0_0101b表示数据写入成功
7.继续读取进行忙检测（读到0x00表示SD卡正在忙状态，即DO拉低），当读到0xFF表示写入操作完成
8.如果想写入下一扇区数据，重复2~7步骤
9.写结束指令0xFD,
10.进行忙检测直到读取到0xFF写操作结束
11.拉高CS,发送8个时钟周期
*/

    uint8_t response=0;
    uint8_t response_wr=0; // 写操作成功影响
    unsigned int i,n,retrys;
    uint8_t crc[2];
    uint8_t rcode=0;

    SD_CS = 0;
    SD_Command(CMD25_WRITE_MULTIPLE_BLOCK, address, 0xFF); // CMD25 : 多块写入
    
    retrys = 1000;
    do {
        response = SD_Response();   // 等待回复0x00表示成功
    }while((response != 0x00)&&--retrys);
    
    if (response != 0x00) {
        // 出错
        rcode = 1;
        goto exit;
    }

    for (n=0; n<block_cnt; n++) {
        // 写入若干时钟周期,这里写入10个字节
        retrys = 10;
        do {
            SD_Write(0xFF);
        }while(retrys--);
        // 写入开始字节0xFC块头部，后面跟512字节数据+2字节CRC数据
        SD_Write(0xFC);

        // 写入512字节数据
        for(i=0; i<512; i++)
        {
            SD_Write(buffer[n*512+i]);
        }

        // 写入2字节CRC
        SD_Write(0xFF);
        SD_Write(0xFF);

        // 读取
        response_wr = SD_Read()&0x0F;  //写入CRC码后SD卡会回应一个xxx0,1001   之后SD卡会把DO引脚拉低处于忙状态，知道释放DO引脚表示写入操作完成
        retrys = 5000;
        do {
            response = SD_ReadWrite(0xFF);  // 读到0x00表示SD卡忙状态，其他表示写入操作完成
        }while((0x00==response)&&--retrys);

        if (response_wr == 0x05) {
            // 成功
            rcode = 0;
        } else {
            // 出错
            rcode = 1;
            goto exit;
        }
    }

    // 写入多块写入停止字节0xFD
    SD_Write(0xFD);
    retrys = 10000;
    do {
        response = SD_Response();
    }while((response!=0x00)&&--retrys);

    // 检测忙信号，此时DO一直为低电平，直到为高电平 表示写入操作完成
    retrys = 10000;
    do {
        response = SD_ReadWrite(0xFF);
    }while((response==0x00)&&--retrys);
    
    if (response!=0xFF) {
        rcode = 1;  // 出错
    }

exit:
    SD_CS = 1;
    SD_Write(0xFF);
    return rcode;
}

uint8_t SD_GetStatus(uint8_t istask)
{
    uint8_t i;
    uint8_t response;
    unsigned int retrys;
    uint8_t R2[2];

    SD_CS = 0;
    SD_Command(CMD13_SEND_STATUS, 0, 0xFF);
    response = SD_Response();
    if (0x00 != response) {
        return 1;
    }

    R2[0] = SD_Read();
    R2[1] = SD_Read();
    
    SD_CS = 1;
    SD_ReadWrite(0xFF);

    log_d("STATUS 0x:%02X%02X\n", R2[0], R2[1]);
}

uint8_t SD_GetCardInfo(void)
{

    uint8_t i;
    uint8_t response;
    uint16_t retrys;

    uint8_t csd_ver;
    uint8_t CSD_Tab[16];
    uint8_t CID_Tab[16];
    uint8_t CRC[2];

    uint8_t temp_u8;
    uint16_t temp_u16;
    uint32_t temp_u32;

    // 读取CSD和CID类似单块读取，发送CMD9、CMD10命令读取到开始字节0xFE + 16字节数据 + 2字节CRC

    SD_CS = 0;
    /* Send CMD9 Read CSD */
    SD_Command(CMD9_SEND_CSD, 0, 0xFF);
    response = SD_Response();
    if (0x00 != response) {
        return 1;
    }

    // 等待读到开始字节0XFE
    retrys = 1000;
    do {
        response = SD_ReadWrite(0xFF); 
    }while((0xFE!=response)&&retrys--);

    if (0xFE != response) {
        return 2;
    }

    // TODO:读取16字节CSD寄存器值
    for (i=0; i<16; i++) {
        CSD_Tab[i] = SD_Read();
    }
    // 读取2字节CRC
    CRC[0] = SD_Read();
    CRC[1] = SD_Read();
    SD_CS = 1;
    SD_ReadWrite(0xFF);

    /** ------------------------------------------------ **/
    SD_CS = 0;
    /* Send CMD10 Read CID */
    SD_Command(CMD10_SEND_CID, 0, 0xFF);
    response = SD_Response();
    if (0x00 != response) {
        return 1;
    }

    // 等待读到开始字节0XFE
    retrys = 1000;
    do {
        response = SD_ReadWrite(0xFF); 
    }while((0xFE != response)&&retrys--);
    if (0xFE != response) {
        return 2;
    }

    // TODO:读取16字节CID寄存器值
    for (i=0; i<16; i++) {
        CID_Tab[i] = SD_Read();
    }
    // 读取2字节CRC
    CRC[0] = SD_Read();
    CRC[1] = SD_Read();

    SD_CS = 1;
    SD_ReadWrite(0xFF);
   

    // 解析CSD数据
#if 1   // 打印CSD数据
    log_d("\nCSD:0x");
    for (i=0; i<16; i++) {
        log_d("%02X", CSD_Tab[i]);
    }
    log_d("\n");
#endif
    csd_ver = ((CSD_Tab[0]>>6)&0x03); // 2bit [127:126]
    sd_cardinf.csd.csd_struct = csd_ver;

    if (E_CSD_VER_1DOT0 == csd_ver) {
        // CSD Version is 1.0  SDSC: Standard Capacity
        log_d("CSD Version is 1.0  SDSC: Standard Capacity\n");

    } else if (E_CSD_VER_2DOT0 == csd_ver) {
        // CSD Version is 2.0  SDHC: High Capacity and  SDXC:Extended Capacity
        log_d("CSD Version is 2.0  SDHC: High Capacity and  SDXC:Extended Capacity\n");
        // memcpy(&sd_cardinf.csd, CSD_Tab, 16);

        sd_cardinf.csd.TAAC = CSD_Tab[1];   // 8 bit[119:112]
        sd_cardinf.csd.NSAC = CSD_Tab[2];   // 8 bit[111:104]
        sd_cardinf.csd.TRAN_SPEED = CSD_Tab[3]; // 8 bit[103:96]

        sd_cardinf.csd.CCC = (uint16_t)(((((uint16_t)CSD_Tab[4]<<8)|CSD_Tab[5])>>4)&0x0FFF);
        sd_cardinf.csd.READ_BL_LEN = CSD_Tab[5]&0x0F; 

        sd_cardinf.csd.READ_BL_PARTIAL = (CSD_Tab[6]>>7)&0x01;
        sd_cardinf.csd.WRITE_BLK_MISALIGN = (CSD_Tab[6]>>6)&0x01;
        sd_cardinf.csd.READ_BLK_MISALIGN = (CSD_Tab[6]>>5)&0x01;
        sd_cardinf.csd.DSR_IMP = (CSD_Tab[6]>>4)&0x01;

        sd_cardinf.csd.C_SIZE = (uint32_t)(((uint32_t)CSD_Tab[7]<<16)|((uint32_t)CSD_Tab[8]<<8)|CSD_Tab[9])&0x3FFFFF;
        
        sd_cardinf.csd.EARSE_BLK_EN = (uint8_t)(CSD_Tab[10]>>6)&0x01;

        temp_u16 = (((uint16_t)CSD_Tab[10]<<8)|CSD_Tab[11]);
        sd_cardinf.csd.SECTOR_SIZE = (temp_u16>>8)&0x7F;
        sd_cardinf.csd.WP_GRP_SIZE = (uint8_t)(CSD_Tab[11]&0x7F);

        sd_cardinf.csd.WP_GRP_ENABLE = (uint8_t)(CSD_Tab[12]>>7)&0x01;
        sd_cardinf.csd.R2W_FACTOR = (uint8_t)(CSD_Tab[12]>>2)&0x07;

        temp_u16 = (((uint16_t)CSD_Tab[12]<<8)|CSD_Tab[13]);
        sd_cardinf.csd.WRITE_BL_LEN = ((uint8_t)(temp_u16>>6)&0x0F);
        sd_cardinf.csd.WRITE_BL_PARTIAL = (uint8_t)((temp_u16>>5)&0x01);

        sd_cardinf.csd.FILE_FORMAT_GRP = (uint8_t)(CSD_Tab[14]>>7)&0x01;
        sd_cardinf.csd.COPY = (uint8_t)(CSD_Tab[14]>>6)&0x01;
        sd_cardinf.csd.PERM_WRITE_PROTECT = (uint8_t)(CSD_Tab[14]>>5)&0x01;
        sd_cardinf.csd.TMP_WRITE_PROTECT = (uint8_t)(CSD_Tab[14]>>4)&0x01;
        sd_cardinf.csd.FILE_FORMAT = (uint8_t)(CSD_Tab[14]>>2)&0x03;
        sd_cardinf.csd.WP_UPC = (CSD_Tab[14]>>1)&0x01;
        
        sd_cardinf.csd.CRC = (uint8_t)((CSD_Tab[15]>>1)&0x7F);

        sd_cardinf.capacity = (uint32_t)((sd_cardinf.csd.C_SIZE+1)*512);

        log_d("csd_struct:%d\n", sd_cardinf.csd.csd_struct);
        log_d("TAAC:%02X\n", sd_cardinf.csd.TAAC);
        log_d("NSAC:%02X\n", sd_cardinf.csd.NSAC);
        log_d("TRAN_SPEED:%02X\n", sd_cardinf.csd.TRAN_SPEED);
        log_d("CCC:%X\n", sd_cardinf.csd.CCC);
        log_d("READ_BL_LEN:%d\n", sd_cardinf.csd.READ_BL_LEN);
        log_d("READ_BL_PARTIAL:%d\n", (int)sd_cardinf.csd.READ_BL_PARTIAL);
        log_d("WRITE_BLK_MISALIGN:%d\n", (int)sd_cardinf.csd.WRITE_BLK_MISALIGN);
        log_d("READ_BLK_MISALIGN:%d\n", sd_cardinf.csd.READ_BLK_MISALIGN);
        log_d("DSR_IMP:%d\n", sd_cardinf.csd.DSR_IMP);
        log_d("C_SIZE:%d\n", sd_cardinf.csd.C_SIZE);
        log_d("EARSE_BLK_EN:%d\n", sd_cardinf.csd.EARSE_BLK_EN);
        log_d("SECTOR_SIZE:%d\n", sd_cardinf.csd.SECTOR_SIZE);
        log_d("WP_GRP_SIZE:%d\n", sd_cardinf.csd.WP_GRP_SIZE);
        log_d("WP_GRP_ENABLE:%d\n", sd_cardinf.csd.WP_GRP_ENABLE);
        log_d("R2W_FACTOR:%d\n", sd_cardinf.csd.R2W_FACTOR);
        log_d("WRITE_BL_LEN:%d\n", sd_cardinf.csd.WRITE_BL_LEN);
        log_d("WRITE_BL_PARTIAL:%d\n", sd_cardinf.csd.WRITE_BL_PARTIAL);
        log_d("FILE_FORMAT_GRP:%d\n", sd_cardinf.csd.FILE_FORMAT_GRP);
        log_d("COPY:%d\n", sd_cardinf.csd.COPY);
        log_d("PERM_WRITE_PROTECT:%d\n", sd_cardinf.csd.PERM_WRITE_PROTECT);
        log_d("TMP_WRITE_PROTECT:%d\n", sd_cardinf.csd.TMP_WRITE_PROTECT);
        log_d("FILE_FORMAT:%d\n", sd_cardinf.csd.FILE_FORMAT);
        log_d("WP_UPC:%d\n", sd_cardinf.csd.WP_UPC);

        log_d("capacity:%lu\n", sd_cardinf.capacity);

    } else if (E_CSD_VER_3DOT0 == csd_ver) {
        // CSD Version is 3.0  SDUC: Ultra Capacity
        log_d("CSD Version is 3.0  SDUC: Ultra Capacity\n");

    }


    // 解析CID数据
#if 1   // 打印CID数据
    log_d("\n\nCID:0x");
    for (i=0; i<16; i++) {
        log_d("%02X", CID_Tab[i]);
    }
    log_d("\n");
#endif
    sd_cardinf.cid.MID    = CID_Tab[0];    // 8bit  Bit[127:120]
    
    sd_cardinf.cid.OID[0] = CID_Tab[1];    // 16bit Bit[119:104]
    sd_cardinf.cid.OID[1] = CID_Tab[2];
    sd_cardinf.cid.OID[2] = '\0';

    sd_cardinf.cid.PNM[0] = CID_Tab[3];
    sd_cardinf.cid.PNM[1] = CID_Tab[4];
    sd_cardinf.cid.PNM[2] = CID_Tab[5];
    sd_cardinf.cid.PNM[3] = CID_Tab[6];
    sd_cardinf.cid.PNM[4] = CID_Tab[7];
    sd_cardinf.cid.PNM[5] = '\0';

    sd_cardinf.cid.PRV    = CID_Tab[8];
    sd_cardinf.cid.PSN    = (uint32_t)(((uint32_t)CID_Tab[9]<<24)|((uint32_t)CID_Tab[10]<<16)|((uint32_t)CID_Tab[11]<<8)|CID_Tab[12]);
    sd_cardinf.cid.MDT    = (uint16_t)(((uint16_t)CID_Tab[13]<<8)|CID_Tab[14]);
    sd_cardinf.cid.CRC    = (uint8_t)(CID_Tab[15]>>1);

    log_d("\n");
    log_d("MID:%02X\n", sd_cardinf.cid.MID);
    log_d("OID:%s\n", sd_cardinf.cid.OID);
    log_d("PNM:%s\n", sd_cardinf.cid.PNM);
    log_d("PRV:%02X\n", sd_cardinf.cid.PRV);
    log_d("PSN:%08X\n", sd_cardinf.cid.PSN);
    log_d("MDT: M=%d, Y=%d\n", (int)(sd_cardinf.cid.MDT&0x0F), (int)((sd_cardinf.cid.MDT>>4)&0xFFF)+2000);
    log_d("CRC:%02X\n", sd_cardinf.cid.CRC);

    return 0;
}


// 当命令为CMD0时，CRC固定为0x95，
// 当命令为CMD8时，CRC固定为0x87。

uint8_t SD_Init(void)
{
    unsigned int trials=0;
    uint8_t i,j;
    uint8_t rcode=0;
    uint8_t response=0xFF;
    uint8_t buff[16];

    SD_SpiSpeedSet(0); // SPI 时钟 低速模式 300KHz左右

    // 1.SD卡上电后，先拉高CS,至少发送74个CLK周期SD卡达到正常工作电压和进行同步之后才能操作SD卡
    SD_CS=1;
    for(trials=0; trials<10; trials++)
    {
        SD_Write(0xFF);
    }

    // 2. 设置SD卡进入SPI模式，先拉低CS,再发送CMD0，需要收到回应0x01表示成功进入IDLE状态
    SD_CS=0;
    // Send Command 0  CRC Fixed to 0x95
    SD_Command(CMD0_GO_IDLE_STATE, 0, 0x95);  // CMD0,复位SD卡 应该返回一个R1令牌，且内容为0x01=SD卡复位成功
#if 1
    trials = 0;
    while((response=SD_Response()) != 0x01) { // 等待SD卡回应信号,0x01表示成功
        trials++;
        if (trials>100) {
            rcode = 1;  // 失败
            goto err0;
        }
    }
#else
    trials = 1000;
    do {
        response = SD_Response();   // 等待SD卡回应信号,0x01表示成功
    } while((response!=0x01)&&trials--);

    if (0 == trials) {
        rcode = 1;  // 失败
        goto err0;
    }
#endif

    SD_CS = 1;
    SD_Write(0xFF); // 接收完命令响应之后，关片选后写入8个空脉冲，SD卡复位完成


    // 设置SPI模式
    SD_CS = 0;
    // 3. CS=0,发送CMD8,主要查看SD卡的类型，和支持的电压范围，回复0x01表示Ver2.X或更高的版本，否则为MMC卡或者Ver1.X
    // Send Command 8 CRC Fixed to 0x87  接收 R7 响应
    SD_Command(CMD8_SEND_IF_COND, VOLTAGE_PATTERN, 0x87);  
    for (i=0; i<5; i++) {
        buff[i] = SD_Read();    // 读取5个字节CMD8响应数据
    }

    // 4. CS=1,关片选后写入8个空脉冲，SD卡复位完成 
    SD_CS = 1;
    SD_Write(0xFF); 

    log_d("CMD8  IF_COND:0x%02X%02X%02X%02X%02X\n", buff[0], buff[1], buff[2], buff[3], buff[4]);
    // 如果是2.0版本的SD卡，就需要循环发送CMD55+ CMD41命令等待2.0卡初始化成功，如果ACMD41命令的返回值等于0就表示卡复位成功。
    if (buff[0] == 0x01 && buff[4] == 0xAA) {  
        // buff[0] == 0x01 : 表示卡支持CMD8命令
        // buff[4] == 0xAA : 匹配成功
        // 卡是否支持2.7~3.6V
        // 卡支持CMD8，可能是 SDHC 或 SDXC 卡
        // 循环发送ACMD41 间隔至少50ms
        uint16_t retry=1000;
        SD_CS = 0;
        do {            
            // CCS=0 SDSC卡，CCS=1 SDHC or SDXC卡
            // ACMD41之后需要不断发送0xFF同时检查接收R1令牌（其实这里的等待接收步骤和CMD0一样），直到R1为0，表示SD卡初始化成功。这里的循环建议添加超时计数。
            // SD_AppCommand(ACMD41_SD_SEND_OP_COND, 0x00000000, 0xFF);    // 对于Ver1.X版本的卡ACMD41参数一般：0x00000000
            SD_AppCommand(ACMD41_SD_SEND_OP_COND, VOLTAGE_WINDOWS, 0xFF);    // 对于Ver2.X及以上更高版本的卡ACMD41参数一般：0x40000000
            response = SD_Read();
            if (response==0x00) {
                break;
            } else {
                delay_ms(50);   // ACMD41 Polling less then 50ms interval       
            }
        } while(retry--);
   
        // ACMD41 返回0x00，表示SD卡初始化成功 
        if (0x00 == response) {
            // CMD58读取OCR
            SD_Command(CMD58_READ_OCR, 0, 0xFF); // CMD58响应R3令牌，共5个字节，高8为为R1令牌，低4字节为OCR寄存器数据
            response = SD_Response(); // 等待SD卡回应信号
            if (0x00 == response)
            {
                // 
                for(j=0; j<4; j++) {    // 读取4个字节OCR寄存器 R3 Responese
                    buff[j]=SD_Read(); 
                }

                // Bit[31]:保留，Bit[30]:1:HC或XC卡  OCR寄存器的30bit， Bit[23:15]电压窗口2.7V~3.6V 每bit电压增加0.1V   Bit[7]:Low Voltage Range
                // uint32_t OCR = (uint32_t)((buff[0]<<24)|(buff[1]<<16)|(buff[2]<<8)|buff[3]);                

                if (buff[0]&0x40) { // OCR BIT[30] 0:SDSC卡，1：SDHC、SDXC或SDUC
                    sd_cardinf.card_type = E_SDCARD_TYPE_SD_V2HC;
                } else {
                    sd_cardinf.card_type = E_SDCARD_TYPE_SD_V2;
                }

                if (buff[0]&0x20) {
                    // BIT[29]:UHS-II Card Status
                }

                if (buff[0]&0x04) {
                    // BIT[24] Switching 1.8V Accepted S18A
                }

                if (buff[3]&0x80) {
                    // BIT[7]  Low Voltage Range
                }
            }      
        }

        SD_CS = 1;
        SD_Write(0xFF); // 关片选后写入8个空脉冲，SD卡复位完成   
        log_d("CMD58  OCR:0x%02X%02X%02X%02X\n", buff[0], buff[1], buff[2], buff[3]);

    } else {
        // 不支持CMD8命令，可能是SDSC卡或MMC卡
        unsigned int retry=1000;
        SD_CS = 0;        
        do {            
            // ACMD41之后需要不断发送0xFF同时检查接收R1令牌（其实这里的等待接收步骤和CMD0一样），直到R1为0，表示SD卡初始化成功。这里的循环建议添加超时计数。
            SD_AppCommand(ACMD41_SD_SEND_OP_COND, 0x00000000, 0xFF);    // 对于Ver1.X版本的卡ACMD41参数一般：0x00000000
            // SD_AppCommand(ACMD41_SD_SEND_OP_COND, 0x40000000, 0xFF);    // 对于Ver2.X及以上更高版本的卡ACMD41参数一般：0x40000000
            response = SD_Read();             
        } while(response && retry--);
    
        // ACMD41 返回0x00，表示SD卡初始化成功
        if (0x00 == response) {
            sd_card_type = E_SDCARD_TYPE_SD_V1;     
        } else {
            retry=1000;
            do{
                SD_Command(CMD1, 0x00000000, 0xFF);
                response = SD_Read();   
            }while(response && retry--);
            if (0x00 == response) {
                sd_card_type = E_SDCARD_TYPE_MMC; // MMC Ver.3
            } else {
                SD_CS = 1;
                SD_Write(0xFF); // 关片选后写入8个空脉冲，SD卡复位完成  
                rcode = 2;
                goto err1;
            }
        }

    }

    // 设置块大小
    SD_CS=0;
    SD_Command(CMD16_SET_BLOCKLEN, 0x00000200, 0xFF);   // 设置块大小为512=0x200  FAT文件系统
    response = SD_Response();
    if (0x00 == response) {
        // 设置块大小成功
        rcode = 0;
    } else {
        // 设置块大小失败
        rcode = 2;
    }

    
err0:
err1:
    SD_CS = 1;
    SD_Write(0xFF); // 关片选后写入8个空脉冲，SD卡复位完成  

    if (0x00 == rcode) {
        SD_SpiSpeedSet(1);  // SPI 时钟 2MHz左右
    }

    return rcode;
}


uint8_t SD_GPIO_Config(void)
{
    // P7_SPEED_LOW(GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);
    P7_SPEED_HIGH(GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);
    P7_PULL_UP_ENABLE(GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);
    P7_DRIVE_MEDIUM(GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);
    // P7_DRIVE_HIGH(GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);

    P7_MODE_OUT_PP(GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);

    // 配置DI为高阻输入模式
    // P7_MODE_IO_PU(GPIO_Pin_4);
    P7_MODE_IN_HIZ(GPIO_Pin_4);
    P7_DIGIT_IN_ENABLE(GPIO_Pin_4);
    P7_PULL_UP_DISABLE(GPIO_Pin_4);
}

#if 0
uint8_t xdata sd_buffer[512*4];   // 512*4字节数据
void SD_ReadWriteTest()
{
    int i; 
    uint8_t rcode=0;

#if 1
    // 写入单扇区操作
    for(i=0; i<512*4;i++)
    {
        sd_buffer[i]=0x5A;
    }

    // 从512000地址写入数据
    rcode = SD_WriteSingleBlock(sd_buffer, 512*1000);
    log_d("\nSD_WriteSingleBlock:%d\n", rcode);

    memset(sd_buffer, 0, sizeof(sd_buffer));
    rcode = SD_ReadSingelBlock(sd_buffer, 512*1000);
    log_d("\nSD_ReadSingelBlock:%d\n", rcode);
    for(i=0; i<512;i++)
    {
        log_d("%x,", sd_buffer[i]);
    }
    log_d("\n\n");
#endif

#if 1
    memset(sd_buffer, 0, sizeof(sd_buffer));
    for(i=0; i<512*4;i++)
    {
        if (i<512) 
            sd_buffer[i]=i;
        else
            sd_buffer[i]=0xAB;
    }
    
    rcode = SD_WriteMultipleBlock(sd_buffer, 512*2000, 4);
    log_d("SD_WriteMultipleBlock:%d\n", rcode);

    memset(sd_buffer, 0, sizeof(sd_buffer));
    rcode = SD_ReadMultipleBlock(sd_buffer, 512*2000, 4);
    log_d("\nSD_ReadSingelBlock:%d\n", rcode);
    for(i=0; i<512*4;i++)
    {
        log_d("%x,", sd_buffer[i]);
    }
    log_d("\n");

#endif
}

void SD_Test(void)
{
    if (SD_Init() == 0) {
        log_d("Find SD Card.\n");

        SD_ReadWriteTest();
    } else {
        log_d("Can't Find SD Card!\n");
    }	
}						
#endif


#endif //TCFG_DRV_SD_CARD_SPI_SUPPORT
